const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const crypto = require('crypto');
const jwt = require('jsonwebtoken');

const { jwtSecret } = require('@root/config');

const UserSchema = new mongoose.Schema(
  {
    method: {
      type: String,
      enum: ['local'],
      required: true
    },
    local: {
      email: {
        type: String,
        lowercase: true,
        match: [/\S+@\S+\.\S+/, '邮箱不符合规范'],
        unique: true,
        sparse: true
      },
      hash: String,
      salt: String
    },
    username: {
      type: String,
      lowercase: true,
      // match: [/^[a-zA-Z0-9]+$/, 'is invalid']
    },
    bio: {
      type: String,
      default: ''
  },
    image: String,
    followers: { //追随者、关注自己的人
      type: [String]
  },
    favorites: [{type: mongoose.Schema.Types.ObjectId, ref: 'Article' }]
  },
  { timestamps: true }
);
UserSchema.plugin(uniqueValidator, { message: 'is already taken.' });


UserSchema.pre('save', async function(next) {
  try {
    if (this.method === 'local') {
      await this.setPassword(this.local.hash);
    } else {
      // TODO:
      this.username = this[this.method].email.split('@')[0];
    }
  } catch (error) {
    next(error);
  }

  next();
});

UserSchema.methods.setPassword = function(password) {
  this.local.salt = crypto.randomBytes(16).toString('hex');
  this.local.hash = crypto
    .pbkdf2Sync(password, this.local.salt, 10000, 512, 'sha512')
    .toString('hex');
};

UserSchema.methods.validPassword = function(password) {
  const hash = crypto
    .pbkdf2Sync(password, this.local.salt, 10000, 512, 'sha512')
    .toString('hex');
  return this.local.hash === hash;
};

// 生成token
UserSchema.methods.generateJWT = function() {
  const today = new Date();
  let exp = new Date(today);
  exp.setDate(today.getDate() + 60);

  return jwt.sign(
    {
      id: this._id,
      username: this.username,
      exp: parseInt(exp.getTime() / 1000)
    },
    jwtSecret
  );
};

// 登录后返回token
UserSchema.methods.toAuthJSON = function() {
  return {
    username: this.username,
    email: this[this.method].email,
    token: this.generateJWT(),
    bio:this.bio,
    image: this.image || `${process.env.UPLOAD_URL}/avatar_default.png`
  };
};

UserSchema.methods.toProfileJSONFor = function() {
  return {
    email: this[this.method].email,
    username: this.username,
    bio:this.bio,
    image:
      this.image || 'https://static.productionready.io/images/smiley-cyrus.jpg',
  };
};

UserSchema.methods.assertFollower = function (userId) {
  return this.followers.includes(userId)
}

UserSchema.methods.addFollower = async function(followerId){
  if(!this.followers.includes(followerId)){
    this.followers.push(followerId)
    await this.save()
  }
}

UserSchema.methods.removeFollower = async function (followerId) {
  for (let i = 0; i < this.followers.length; i++) {
      if (this.followers[i] === followerId) {
          this.followers.splice(followerId, 1)
          await this.save()
      }
  }
}

UserSchema.methods.favorite = function(id) {
  if (!this.favorites.includes(id)) {
    this.favorites.push(id);
  }

  return this.save();
};

UserSchema.methods.unfavorite = function(id) {
  this.favorites.remove(id);
  return this.save();
};

UserSchema.methods.isFavorite = function(id) {
  return this.favorites.some(
    favoriteId => favoriteId.toString() === id.toString()
  );
};

UserSchema.pre('remove', function(next) {
  this.model('Article').deleteMany({ author: this._id }, next);
});

module.exports = mongoose.models.User || mongoose.model('User', UserSchema);


